#pragma once
/**
 ********************************************************************************************************
 *                                               示例代码
 *                                             EXAMPLE  CODE
 *
 *                      (c) Copyright 2024; SaiShu.Lcc.; Leo;
 *https://bjsstech.com 版权所属[SASU-北京赛曙科技有限公司]
 *
 *            The code is for internal use only, not for commercial
 *transactions(开源学习,请勿商用). The code ADAPTS the corresponding hardware
 *circuit board(代码适配百度Edgeboard-智能汽车赛事版), The specific details
 *consult the professional(欢迎联系我们,代码持续更正，敬请关注相关开源渠道).
 *********************************************************************************************************
 * @file uart.hpp
 *
 * @author Leo
 * @brief 上下位机串口通信协议
 * @version 0.1
 * @date 2023-12-26
 *
 * @copyright Copyright (c) 2023
 *
 */
#include <iostream>               // 输入输出类
#include <libserial/SerialPort.h> // 串口通信
#include <math.h>                 // 数学函数类
#include <stdint.h>               // 整型数据类
#include <string.h>
#include <thread>

using namespace LibSerial;
using namespace std;

class Uart {
private:
  /**
   * @brief 串口通信结构体
   *
   */

  std::unique_ptr<std::thread> threadRec; // 串口接收子线程
  std::shared_ptr<SerialPort> serialPort = nullptr;
  std::string portName; // 端口名字
  bool isOpen = false;

  // /**
  //  * @brief 串口接收字节数据
  //  *
  //  * @param charBuffer
  //  * @param msTimeout
  //  * @return int
  //  */
  // int receiveBytes(unsigned char &charBuffer, size_t msTimeout = 0) {
  //   /*try检测语句块有没有异常。如果没有发生异常,就检测不到。
  //   如果发生异常，則交给 catch 处理，执行 catch 中的语句* */
  //   try {
  //     /*从串口读取一个数据,指定msTimeout时长内,没有收到数据，抛出异常。
  //     如果msTimeout为0，则该方法将阻塞，直到数据可用为止。*/
  //     serialPort->ReadByte(charBuffer, msTimeout); // 可能出现异常的代码段
  //   } catch (const ReadTimeout &) // catch捕获并处理 try 检测到的异常。
  //   {
  //     // std::cerr << "The ReadByte() call has timed out." << std::endl;
  //     return -2;
  //   } catch (const NotOpen &) // catch()中指明了当前 catch 可以处理的异常类型
  //   {
  //     std::cerr << "Port Not Open ..." << std::endl;
  //     return -1;
  //   }
  //   return 0;
  // };

  /**
   * @brief
   *
   * @param data
   * @return int
   */
  int transmitByte(unsigned char data) {
    // try检测语句块有没有异常
    try {
      serialPort->WriteByte(data); // 写数据到串口
    } catch (const std::runtime_error &) // catch捕获并处理 try 检测到的异常。
    {
      std::cerr << "The Write() runtime_error." << std::endl;
      return -2;
    } catch (const NotOpen &) // catch捕获并处理 try 检测到的异常。
    {
      std::cerr << "Port Not Open ..." << std::endl;
      return -1;
    }
    serialPort->DrainWriteBuffer(); // 等待，直到写缓冲区耗尽，然后返回。
    return 0;
  }

public:
  // 定义构造函数
  Uart(const std::string &port) : portName(port){};
  // 定义析构函数
  ~Uart() { close(); };

public:
  /**
   * @brief 启动串口通信
   *
   * @param port 串口号
   * @return int
   */
  int open(void) {
    serialPort = std::make_shared<SerialPort>();
    if (serialPort == nullptr) {
      std::cerr << "Serial Create Failed ." << std::endl;
      return -1;
    }
    // try检测语句块有没有异常
    try {
      serialPort->Open(portName);                     // 打开串口
      serialPort->SetBaudRate(BaudRate::BAUD_115200); // 设置波特率
      serialPort->SetCharacterSize(CharacterSize::CHAR_SIZE_8); // 8位数据位
      serialPort->SetFlowControl(FlowControl::FLOW_CONTROL_NONE); // 设置流控
      serialPort->SetParity(Parity::PARITY_NONE);                 // 无校验
      serialPort->SetStopBits(StopBits::STOP_BITS_1); // 1个停止位
    } catch (const OpenFailed &) // catch捕获并处理 try 检测到的异常。
    {
      std::cerr << "Serial port: " << portName << "open failed ..."
                << std::endl;
      isOpen = false;
      return -2;
    } catch (const AlreadyOpen &) // catch捕获并处理 try 检测到的异常。
    {
      std::cerr << "Serial port: " << portName << "open failed ..."
                << std::endl;
      isOpen = false;
      return -3;
    } catch (...) // catch捕获并处理 try 检测到的异常。
    {
      std::cerr << "Serial port: " << portName << " recv exception ..."
                << std::endl;
      isOpen = false;
      return -4;
    }

    return 0;
  }


  /**
   * @brief 关闭串口通信
   *
   */
  void close(void) {
    printf(" uart thread exit!\n");
    if (serialPort != nullptr) {
      serialPort->Close();
      serialPort = nullptr;
    }
    isOpen = false;
  }

  /**
   * @brief 串口发送数据：speedcar速度；anglepwm舵机；stopstate(1停车，0运行)；
   *
   */
  void sendpwm(int speedcar,int anglepwm,bool buzzerstate) {
    int speedpwm = abs(speedcar);
      transmitByte('A');
      if(speedcar>0)transmitByte(0);
      if(speedcar<0)transmitByte(1);
      transmitByte(speedpwm/10);
      transmitByte(speedpwm%10);
      transmitByte((anglepwm-1000)/100);
      transmitByte(((anglepwm-1000)%100)/10);
      transmitByte(0);
      transmitByte(buzzerstate);
      transmitByte(0);
      transmitByte('B');
    
  }
};
